#!/bin/bash
###############################################################################
#       脚本名称: test_utils_datetime.sh
#       功能描述: 日期时间工具类(utils_datetime.sh)单元测试
#       作者: 林再来
#       日期: 2025-10-20
#       版本: 1.0
#       功能:
#           1、测试日期时间工具的所有核心功能
#           2、验证基础获取、格式转换、差值计算、时区处理等功能
#           3、验证增强功能：工作日计算、节假日判断、年龄星座等
###############################################################################

# 切换到脚本目录
cd "$(dirname "${BASH_SOURCE[0]}")" || exit 1

# 加载测试框架
source ../test_framework.sh

# 加载被测模块
source ../../../scripts/utils/utils_datetime.sh

###############################################################################
# 基础日期时间获取测试
###############################################################################

# 测试: 获取当前日期时间
test_utils_datetime_now() {
    local result
    result=$(utils_datetime_now)
    assert_not_empty "$result" "应该返回当前日期时间"
    assert_matches "$result" "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$" "日期时间格式应该正确"
}

# 测试: 获取当前日期
test_utils_datetime_today() {
    local result
    result=$(utils_datetime_today)
    assert_not_empty "$result" "应该返回当前日期"
    assert_matches "$result" "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" "日期格式应该正确"
}

# 测试: 获取当前时间
test_utils_datetime_time() {
    local result
    result=$(utils_datetime_time)
    assert_not_empty "$result" "应该返回当前时间"
    assert_matches "$result" "^[0-9]{2}:[0-9]{2}:[0-9]{2}$" "时间格式应该正确"
}

# 测试: 获取Unix时间戳
test_utils_datetime_timestamp() {
    local result
    result=$(utils_datetime_timestamp)
    assert_not_empty "$result" "应该返回Unix时间戳"
    assert_matches "$result" "^[0-9]+$" "时间戳应该是数字"
    
    # 验证时间戳是否合理（2025年左右）
    local current_year
    current_year=$(date +%Y)
    local timestamp_year
    timestamp_year=$(date -d "@$result" +%Y)
    assert_equals "$current_year" "$timestamp_year" "时间戳年份应该正确"
}

###############################################################################
# 日期时间格式转换测试
###############################################################################

# 测试: 转换日期时间格式
test_utils_datetime_convert() {
    local result
    result=$(utils_datetime_convert "2025-01-27 10:30:00" "%Y-%m-%d %H:%M:%S" "%Y/%m/%d")
    assert_equals "2025/01/27" "$result" "日期格式转换应该正确"
}

# 测试: Unix时间戳转日期时间
test_utils_datetime_from_timestamp() {
    local result
    result=$(utils_datetime_from_timestamp "1737952200")
    assert_not_empty "$result" "应该返回日期时间"
    assert_matches "$result" "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}$" "日期时间格式应该正确"
}

# 测试: 日期时间转Unix时间戳
test_utils_datetime_to_timestamp() {
    local result
    result=$(utils_datetime_to_timestamp "2025-01-27 10:30:00")
    assert_not_empty "$result" "应该返回Unix时间戳"
    assert_matches "$result" "^[0-9]+$" "时间戳应该是数字"
}

# 测试: 时间戳转换的往返一致性
test_utils_datetime_timestamp_roundtrip() {
    local original_timestamp="1737952200"
    local datetime
    datetime=$(utils_datetime_from_timestamp "$original_timestamp")
    local converted_timestamp
    converted_timestamp=$(utils_datetime_to_timestamp "$datetime")
    assert_equals "$original_timestamp" "$converted_timestamp" "时间戳转换应该保持一致性"
}

###############################################################################
# 日期时间格式化输出测试
###############################################################################

# 测试: 格式化日期时间
test_utils_datetime_format() {
    local result
    result=$(utils_datetime_format "2025-01-27 10:30:00" "%Y年%m月%d日 %H时%M分")
    assert_equals "2025年01月27日 10时30分" "$result" "日期时间格式化应该正确"
}

# 测试: 获取相对时间描述
test_utils_datetime_relative() {
    local result
    result=$(utils_datetime_relative "2025-01-27 10:30:00")
    assert_not_empty "$result" "应该返回相对时间描述"
    assert_contains "$result" "2025" "相对时间描述应该包含年份"
}

###############################################################################
# 日期差/时间差值计算测试
###############################################################################

# 测试: 计算两个日期时间的差值（秒）
test_utils_datetime_diff_seconds() {
    local result
    result=$(utils_datetime_diff_seconds "2025-01-27 10:00:00" "2025-01-27 11:00:00")
    assert_equals "3600" "$result" "一小时应该等于3600秒"
}

# 测试: 计算两个日期时间的差值（天）
test_utils_datetime_diff_days() {
    local result
    result=$(utils_datetime_diff_days "2025-01-01" "2025-01-03")
    assert_equals "2" "$result" "两天差值应该正确"
}

# 测试: 计算日期时间加减
test_utils_datetime_add() {
    local result
    result=$(utils_datetime_add "2025-01-27 10:00:00" "1" "hour")
    assert_matches "$result" "^2025-01-27 11:00:00$" "加一小时应该正确"
    
    result=$(utils_datetime_add "2025-01-27" "7" "day")
    assert_matches "$result" "^2025-02-03" "加七天应该正确"
}

# 测试: 日期时间加减的负数
test_utils_datetime_add_negative() {
    local result
    result=$(utils_datetime_add "2025-01-27 11:00:00" "-1" "hour")
    assert_not_empty "$result" "减一小时应该返回结果"
    assert_contains "$result" "2025-01-27" "结果应该包含正确的日期"
    
    # 验证时间格式是否正确（应该是HH:MM:SS格式）
    if [[ "$result" =~ [0-9]{2}:[0-9]{2}:[0-9]{2} ]]; then
        return 0
    else
        echo "错误: 时间格式不正确，实际结果: $result" >&2
        return 1
    fi
}

###############################################################################
# 时区处理测试
###############################################################################

# 测试: 设置默认时区
test_utils_datetime_set_timezone() {
    utils_datetime_set_timezone "UTC"
    assert_equals "UTC" "$utils_datetime_timezone" "时区应该设置为UTC"
}

# 测试: 获取当前时区
test_utils_datetime_get_timezone() {
    local result
    result=$(utils_datetime_get_timezone)
    assert_not_empty "$result" "应该返回当前时区"
}

# 测试: 转换时区
test_utils_datetime_convert_timezone() {
    local result
    result=$(utils_datetime_convert_timezone "2025-01-27 10:00:00" "UTC")
    assert_not_empty "$result" "应该返回转换后的时间"
}

# 测试: 无效时区设置
test_utils_datetime_set_invalid_timezone() {
    local original_timezone="$utils_datetime_timezone"
    utils_datetime_set_timezone "Invalid/Timezone" 2>/dev/null
    local exit_code=$?
    assert_false $exit_code "无效时区设置应该返回错误"
    # 恢复原始时区
    utils_datetime_timezone="$original_timezone"
}

###############################################################################
# 工作日计算和节假日判断测试
###############################################################################

# 测试: 判断是否为工作日
test_utils_datetime_is_workday() {
    # 测试工作日（周一）
    utils_datetime_is_workday "2025-01-27"  # 周一
    assert_true $? "周一应该是工作日"
    
    # 测试非工作日（周六）
    utils_datetime_is_workday "2025-01-25"  # 周六
    assert_false $? "周六不应该是工作日"
}

# 测试: 判断是否为节假日
test_utils_datetime_is_holiday() {
    # 测试元旦
    utils_datetime_is_holiday "2025-01-01"
    assert_true $? "元旦应该是节假日"
    
    # 测试普通工作日
    utils_datetime_is_holiday "2025-01-27"
    assert_false $? "普通工作日不应该是节假日"
}

# 测试: 判断是否为营业日
test_utils_datetime_is_business_day() {
    # 测试普通工作日
    utils_datetime_is_business_day "2025-01-28"  # 周二，非节假日
    assert_true $? "普通工作日应该是营业日"
    
    # 测试节假日
    utils_datetime_is_business_day "2025-01-01"  # 元旦
    assert_false $? "节假日不应该是营业日"
}

# 测试: 计算工作日数量
test_utils_datetime_count_workdays() {
    local result
    result=$(utils_datetime_count_workdays "2025-01-01" "2025-01-07")
    assert_not_empty "$result" "应该返回工作日数量"
    assert_matches "$result" "^[0-9]+$" "工作日数量应该是数字"
}

# 测试: 获取下一个工作日
test_utils_datetime_next_workday() {
    local result
    result=$(utils_datetime_next_workday "2025-01-25")  # 周六
    assert_not_empty "$result" "应该返回下一个工作日"
    assert_matches "$result" "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" "返回的应该是日期格式"
}

###############################################################################
# 时间区间生成和序列处理测试
###############################################################################

# 测试: 生成时间序列
test_utils_datetime_generate_sequence() {
    local result
    result=$(utils_datetime_generate_sequence "2025-01-01 00:00:00" "2025-01-01 02:00:00" "hour" "1")
    assert_not_empty "$result" "应该返回时间序列"
    
    local line_count
    line_count=$(echo "$result" | wc -l)
    assert_equals "3" "$line_count" "应该生成3个时间点"
}

# 测试: 生成每日序列
test_utils_datetime_generate_daily_sequence() {
    local result
    result=$(utils_datetime_generate_sequence "2025-01-01" "2025-01-03" "day" "1")
    assert_not_empty "$result" "应该返回日期序列"
    
    local line_count
    line_count=$(echo "$result" | wc -l)
    assert_equals "3" "$line_count" "应该生成3个日期"
}

###############################################################################
# 年龄计算和星座查询测试
###############################################################################

# 测试: 获取年龄
test_utils_datetime_get_age() {
    local result
    result=$(utils_datetime_get_age "1990-01-01" "2025-01-01")
    assert_equals "35" "$result" "1990年出生的人在2025年应该是35岁"
}

# 测试: 获取星座
test_utils_datetime_get_zodiac() {
    local result
    
    # 测试水瓶座
    result=$(utils_datetime_get_zodiac "1" "27")
    assert_equals "水瓶座" "$result" "1月27日应该是水瓶座"
    
    # 测试白羊座
    result=$(utils_datetime_get_zodiac "3" "21")
    assert_equals "白羊座" "$result" "3月21日应该是白羊座"
    
    # 测试狮子座
    result=$(utils_datetime_get_zodiac "8" "15")
    assert_equals "狮子座" "$result" "8月15日应该是狮子座"
}

###############################################################################
# 闰年判断和月份天数计算测试
###############################################################################

# 测试: 判断是否为闰年
test_utils_datetime_is_leap_year() {
    # 测试闰年
    utils_datetime_is_leap_year "2024"
    assert_true $? "2024年应该是闰年"
    
    # 测试非闰年
    utils_datetime_is_leap_year "2023"
    assert_false $? "2023年不应该是闰年"
    
    # 测试世纪年（能被400整除的闰年）
    utils_datetime_is_leap_year "2000"
    assert_true $? "2000年应该是闰年"
    
    # 测试世纪年（不能被400整除的非闰年）
    utils_datetime_is_leap_year "1900"
    assert_false $? "1900年不应该是闰年"
}

# 测试: 获取月份的天数
test_utils_datetime_days_in_month() {
    local result
    
    # 测试1月
    result=$(utils_datetime_days_in_month "2025" "1")
    assert_not_empty "$result" "1月天数应该返回结果"
    assert_matches "$result" "^[0-9]+$" "1月天数应该是数字"
    
    # 测试2月（非闰年）
    result=$(utils_datetime_days_in_month "2023" "2")
    assert_not_empty "$result" "2023年2月天数应该返回结果"
    assert_matches "$result" "^[0-9]+$" "2023年2月天数应该是数字"
    
    # 测试2月（闰年）
    result=$(utils_datetime_days_in_month "2024" "2")
    assert_not_empty "$result" "2024年2月天数应该返回结果"
    assert_matches "$result" "^[0-9]+$" "2024年2月天数应该是数字"
    
    # 测试4月
    result=$(utils_datetime_days_in_month "2025" "4")
    assert_not_empty "$result" "4月天数应该返回结果"
    assert_matches "$result" "^[0-9]+$" "4月天数应该是数字"
}

###############################################################################
# 错误处理测试
###############################################################################

# 测试: 无效日期格式处理
test_utils_datetime_invalid_date_format() {
    utils_datetime_convert "invalid-date" "%Y-%m-%d" "%Y/%m/%d" 2>/dev/null
    assert_false $? "无效日期格式应该返回错误"
}

# 测试: 无效时间戳格式处理
test_utils_datetime_invalid_timestamp() {
    utils_datetime_from_timestamp "invalid" 2>/dev/null
    assert_false $? "无效时间戳应该返回错误"
}

# 测试: 无效参数处理
test_utils_datetime_invalid_params() {
    utils_datetime_diff_seconds "" "" 2>/dev/null
    assert_false $? "空参数应该返回错误"
    
    utils_datetime_add "" "1" "day" 2>/dev/null
    assert_false $? "空基准日期应该返回错误"
}

# 测试: 无效时间单位处理
test_utils_datetime_invalid_unit() {
    utils_datetime_add "2025-01-27" "1" "invalid" 2>/dev/null
    assert_false $? "无效时间单位应该返回错误"
}

###############################################################################
# 边界条件测试
###############################################################################

# 测试: 闰年2月29日
test_utils_datetime_leap_year_feb29() {
    local result
    result=$(utils_datetime_format "2024-02-29" "%Y-%m-%d")
    assert_equals "2024-02-29" "$result" "闰年2月29日应该有效"
}

# 测试: 年份边界
test_utils_datetime_year_boundary() {
    local result
    result=$(utils_datetime_format "1999-12-31 23:59:59" "%Y-%m-%d %H:%M:%S")
    assert_equals "1999-12-31 23:59:59" "$result" "年份边界日期应该正确"
}

# 测试: 月份边界
test_utils_datetime_month_boundary() {
    local result
    result=$(utils_datetime_format "2025-01-31" "%Y-%m-%d")
    assert_equals "2025-01-31" "$result" "月份边界日期应该正确"
}

###############################################################################
# 帮助函数测试
###############################################################################

# 测试: 显示帮助信息
test_utils_datetime_help() {
    local result
    result=$(utils_datetime_help)
    assert_not_empty "$result" "帮助信息不应该为空"
    assert_contains "$result" "utils_datetime_now" "帮助信息应该包含函数名"
    assert_contains "$result" "使用示例" "帮助信息应该包含使用示例"
}

###############################################################################
# 测试运行器
###############################################################################

# 主测试函数
run_all_tests() {
    echo "开始运行 utils_datetime.sh 单元测试..."
    
    # 基础日期时间获取测试
    test_suite_start "基础日期时间获取"
    run_test "获取当前日期时间" test_utils_datetime_now
    run_test "获取当前日期" test_utils_datetime_today
    run_test "获取当前时间" test_utils_datetime_time
    run_test "获取Unix时间戳" test_utils_datetime_timestamp
    test_suite_end
    
    # 日期时间格式转换测试
    test_suite_start "日期时间格式转换"
    run_test "转换日期时间格式" test_utils_datetime_convert
    run_test "Unix时间戳转日期时间" test_utils_datetime_from_timestamp
    run_test "日期时间转Unix时间戳" test_utils_datetime_to_timestamp
    run_test "时间戳转换往返一致性" test_utils_datetime_timestamp_roundtrip
    test_suite_end
    
    # 日期时间格式化输出测试
    test_suite_start "日期时间格式化输出"
    run_test "格式化日期时间" test_utils_datetime_format
    run_test "获取相对时间描述" test_utils_datetime_relative
    test_suite_end
    
    # 日期差/时间差值计算测试
    test_suite_start "日期差/时间差值计算"
    run_test "计算日期时间差值（秒）" test_utils_datetime_diff_seconds
    run_test "计算日期时间差值（天）" test_utils_datetime_diff_days
    run_test "计算日期时间加减" test_utils_datetime_add
    run_test "日期时间加减负数" test_utils_datetime_add_negative
    test_suite_end
    
    # 时区处理测试
    test_suite_start "时区处理"
    run_test "设置默认时区" test_utils_datetime_set_timezone
    run_test "获取当前时区" test_utils_datetime_get_timezone
    run_test "转换时区" test_utils_datetime_convert_timezone
    run_test "无效时区设置" test_utils_datetime_set_invalid_timezone
    test_suite_end
    
    # 工作日计算和节假日判断测试
    test_suite_start "工作日计算和节假日判断"
    run_test "判断是否为工作日" test_utils_datetime_is_workday
    run_test "判断是否为节假日" test_utils_datetime_is_holiday
    run_test "判断是否为营业日" test_utils_datetime_is_business_day
    run_test "计算工作日数量" test_utils_datetime_count_workdays
    run_test "获取下一个工作日" test_utils_datetime_next_workday
    test_suite_end
    
    # 时间区间生成和序列处理测试
    test_suite_start "时间区间生成和序列处理"
    run_test "生成时间序列" test_utils_datetime_generate_sequence
    run_test "生成每日序列" test_utils_datetime_generate_daily_sequence
    test_suite_end
    
    # 年龄计算和星座查询测试
    test_suite_start "年龄计算和星座查询"
    run_test "获取年龄" test_utils_datetime_get_age
    run_test "获取星座" test_utils_datetime_get_zodiac
    test_suite_end
    
    # 闰年判断和月份天数计算测试
    test_suite_start "闰年判断和月份天数计算"
    run_test "判断是否为闰年" test_utils_datetime_is_leap_year
    run_test "获取月份的天数" test_utils_datetime_days_in_month
    test_suite_end
    
    # 错误处理测试
    test_suite_start "错误处理"
    run_test "无效日期格式处理" test_utils_datetime_invalid_date_format
    run_test "无效时间戳格式处理" test_utils_datetime_invalid_timestamp
    run_test "无效参数处理" test_utils_datetime_invalid_params
    run_test "无效时间单位处理" test_utils_datetime_invalid_unit
    test_suite_end
    
    # 边界条件测试
    test_suite_start "边界条件"
    run_test "闰年2月29日" test_utils_datetime_leap_year_feb29
    run_test "年份边界" test_utils_datetime_year_boundary
    run_test "月份边界" test_utils_datetime_month_boundary
    test_suite_end
    
    # 帮助函数测试
    test_suite_start "帮助函数"
    run_test "显示帮助信息" test_utils_datetime_help
    test_suite_end
    
    # 显示测试报告
    print_test_summary
    exit_with_test_result
}

# 如果脚本直接运行，执行所有测试
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    run_all_tests
fi
